using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net;
using System.Web;
using OpenWaves.ActivityFeed.Web.Controls;
using OpenWaves.ActivityFeed.Web.Handler;

namespace OpenWaves.ActivityFeed.Web.Modules
{
    public class UpdatesModule : RestModule
    {
        private readonly IUserIdentityProvider identityProvider;
        private readonly IActivityFeedService activityFeedService;
        private readonly IUserGroupMembershipProvider groupMembershipProvider;
        private readonly IUpdateDtoBuilder updateDtoBuilder;

        public UpdatesModule(IUserIdentityProvider identityProvider, IActivityFeedService activityFeedService,
                             IUserGroupMembershipProvider groupMembershipProvider, IUpdateDtoBuilder updateDtoBuilder)
        {
            this.groupMembershipProvider = groupMembershipProvider;
            this.activityFeedService = activityFeedService;
            this.identityProvider = identityProvider;
            this.updateDtoBuilder = updateDtoBuilder;

            this.Get("/activityFeed/updates", (request, paremeters) => GetUpdates(request));

            this.Post("/activityFeed/updates", (request, p) =>
                                                   {
                                                       var dto = request.DeserializeBody<StatusUpdateDto>();
                                                       Contract.Assert(String.IsNullOrEmpty(dto.Text) == false);

                                                       var newTopics =
                                                           new List<Topic>(new[]
                                                                               {
                                                                                   Topic.FromUserId(
                                                                                       identityProvider.Identity.Name)
                                                                               });
                                                       if (dto.NewTopics != null)
                                                       {
                                                           newTopics.AddRange(dto.NewTopics);
                                                       }

                                                       //TODO: possibility of mark topic update as not public with userGroups

                                                       var update = activityFeedService.PublishUpdate(
                                                           new Post(dto.Text), identityProvider.Identity.Name,
                                                           dto.Source,
                                                           newTopics, true, Enumerable.Empty<UserGroup>());

                                                       var updateDto = this.updateDtoBuilder.BuildUpdateDto(update);

                                                       return new JsonResult(Result.Ok(updateDto));
                                                   });

            this.Delete("/activityFeed/updates/{updateId}",
                        (request, p) => DeleteUpdate(p, activityFeedService, identityProvider));
        }

        private static IActionResult DeleteUpdate(IDictionary<string, string> p,
                                                  IActivityFeedService activityFeedService,
                                                  IUserIdentityProvider identityProvider)
        {
            string updateId = p["updateId"];
            Contract.Assert(String.IsNullOrEmpty(updateId) == false);

            Update update =
                activityFeedService.GetUpdate(Url.Decode(updateId));
            if (update == null)
                return new HttpResult(HttpStatusCode.NotFound);

            if (update.CanBeDeletedBy(identityProvider.Identity.Name) ==
                false)
                return new HttpResult(HttpStatusCode.Forbidden);

            activityFeedService.RemoveUpdate(update);

            return new JsonResult(Result.Ok());
        }

        private IActionResult GetUpdates(HttpRequestBase request)
        {
            var query = Url.FromUri(request.Url).Query;

            var pagerInfo = PaginationRequest.FromQuery(query);

            var searchTerm = query.ContainsKey("searchTerm") ? query["searchTerm"] : null;

            var topicsFilter = query.ContainsKey("topicsFilter") ? query["topicsFilter"].Trim() : null;
#if NET_40_OR_GREATER
            var topicsFilterList = String.IsNullOrWhiteSpace(topicsFilter)
                                       ? Enumerable.Empty<Topic>()
                                       : topicsFilter.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries).
                                             Select(t => new Topic(t));
#else
            var topicsFilterList = String.IsNullOrEmpty(topicsFilter) || topicsFilter.Trim() == ""
                                       ? Enumerable.Empty<Topic>()
                                       : topicsFilter.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries).Select(t=> new Topic(t));
#endif
            // default feedType is personal
            FeedType feedType;
            if (query.ContainsKey("feedType"))
            {
                switch (query["feedType"])
                {
                    case "global":
                        feedType = FeedType.Global;
                        break;
                    case "custom":
                        feedType = FeedType.Custom;
                        break;
                    default:
                        feedType = FeedType.Personal;
                        break;
                }
            }
            else
            {
                feedType = FeedType.Personal;
            }

            var customFeedTypeName = query.ContainsKey("customFeedTypeName")
                                         ? query["customFeedTypeName"]
                                         : string.Empty;

            var updatesBuilder =
                ServiceLocator.Resolve<IActivityFeedBuilderFactory>().Create(feedType, customFeedTypeName,
                                                                             this.activityFeedService,
                                                                             this.updateDtoBuilder,
                                                                             this.identityProvider.Identity.Name);
            updatesBuilder.PaginationRequest = pagerInfo;
            updatesBuilder.SearchTerms = searchTerm;
            updatesBuilder.UserGroups = groupMembershipProvider.UserGroups;
            updatesBuilder.TopicsFilter = topicsFilterList;

            PaginationStatus status;
            var updates = updatesBuilder.BuildActivityFeed(out status);

            return new JsonResult(Result.Ok(updates, status));
        }
    }
}